package com.eling.elcms.travel.model;

import com.eling.elcms.basedoc.model.EnumSerializer;
import com.eling.elcms.core.dao.annotation.Between;
import com.eling.elcms.core.dao.annotation.CriteriaEnhancer;
import com.eling.elcms.core.dao.annotation.CriteriaEnhancers;
import com.eling.elcms.core.dao.annotation.In;
import com.eling.elcms.core.dao.hibernate.OrderCriteriaEnhancer;
import com.eling.elcms.core.dao.hibernate.search.EnumBridge;
import com.eling.elcms.core.model.BaseModel;
import com.eling.elcms.ordermanager.model.ServicePoint;
import com.eling.elcms.privilege.service.impl.CommonPrivilegeCriteriaEnhancer;
import com.eling.elcms.system.model.CommonUser;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.hibernate.search.annotations.*;

import javax.persistence.*;
import java.util.Date;
import java.util.Set;

/**
 * 入住准备落实
 * 
 * @author wulina
 *
 */
@Entity
@Table(name = "travel_checkinimplement")
@Indexed
@CriteriaEnhancers(criteriaEnhancers = { @CriteriaEnhancer(impl = OrderCriteriaEnhancer.class),
		@CriteriaEnhancer(impl = CommonPrivilegeCriteriaEnhancer.class, parameter = "servicepoint:servicePoint") })
public class CheckInImplement extends BaseModel {

	private static final long serialVersionUID = 8301877158183067309L;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@DocumentId
	@In
	private Long pkCIImplement;

	@OneToMany
	@JoinTable(name = "bd_checkinimplement_cardispatchbill",
	joinColumns = {@JoinColumn(name = "pkCIImplement")},
	inverseJoinColumns = {@JoinColumn(name = "pkCarDispatchBill")})
	@IndexedEmbedded(depth = 1)
	private Set<CarDispatchBill> carDispatchBill;
	
	/** 服务点 */
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "pkServicePoint")
	@IndexedEmbedded(depth = 1)
	private ServicePoint servicePoint;

	/** 组团预约 */
	@OneToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "pkGroupReserve")
	@IndexedEmbedded(depth = 1)
	private GroupReserve groupReserve;

	/** 散客团预约 */
	@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
	@JoinColumn(name = "pkNonMemGroupReserve")
	@IndexedEmbedded(depth = 1)
	private NonMemGroupReserve nonMemGroupReserve;

	/** 预约来源（散客团，机构和联盟团） */
	@Enumerated(EnumType.STRING)
	@Field
	@FieldBridge(impl = EnumBridge.class)
	@In
	private DataSource dataSource;

	/** 房间入住情况 */
	@OneToMany(cascade = CascadeType.MERGE)
	@JoinColumn(name = "pkCIImplement")
	@IndexedEmbedded(depth = 1)
	private Set<RoomPersonalInfo> roomPersonalInfos;

	/** 房间整体落实状态(子状态) */
	@Enumerated(EnumType.STRING)
	@Field
	@In
	@FieldBridge(impl = EnumBridge.class)
	private CheckStatus roomStatus;
	
	/** 会议 */
	@OneToMany(mappedBy = "checkInImplement")
	@IndexedEmbedded(depth = 1)
	private Set<CheckInMeeting> checkInMeetings;

	/** 餐饮 */
	@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
	@JoinColumn(name = "pkCheckInDinner")
	@IndexedEmbedded(depth = 1)
	private CheckInDinner checkInDinner;

	/** 入住派车处理 */
	@OneToMany(mappedBy = "checkInImplement")
	@IndexedEmbedded(depth = 1)
	private Set<CheckInCar> checkInCar;

	/** 入住房间处理 */
	@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
	@JoinColumn(name = "pkSignUpRoom")
	@IndexedEmbedded(depth = 1)
	private SignUpRoom signUpRoom;

	/** 入住落实状态 */
	@Enumerated(EnumType.STRING)
	@Field
	@FieldBridge(impl = EnumBridge.class)
	@In
	private CheckStatus status;

	// TODO 以后把结算状态，日期，方式，备注单独提出去 ljz
	/** 结算状态 */
	@Enumerated(EnumType.STRING)
	@In
	@FieldBridge(impl = EnumBridge.class)
	private StatementStatus statementStatus;

	/** 结算日期 */
	@Column
	@Field
	@Between
	private Date statementDate;

	/** 结算方式 */
	@ElementCollection(fetch = FetchType.EAGER)
	@Enumerated(EnumType.STRING)
	@CollectionTable(name = "travel_org_paymentmethods", joinColumns = @JoinColumn(name = "pkCIImplement"))
	@Column(name = "paymentMethods", nullable = false)
	private Set<PaymentMethod> paymentMethods;

	@JsonSerialize(using = EnumSerializer.class)
	public enum PaymentMethod {
		Cash("现金"), WipeCard("刷卡"), Transfer("转账"), OnCredit("挂账");
		private String display;

		PaymentMethod(String display) {
			this.display = display;
		}

		public String getDisplay() {
			return display;
		}
	}

	/** 实收金额合计 */
	@Column
	private Double balance;
	
	/**  会员房价 */
	@Column
	private Double vipPrice;

	/** 结算合计备注 */
	@Column
	private String description;
	
	

	/** 状态 */
	@Enumerated(EnumType.STRING)
	@Field
	@In
	@FieldBridge(impl = EnumBridge.class)
	private ConfirmStatus confirmStatus;

	@JsonSerialize(using = EnumSerializer.class)
	public static enum ConfirmStatus {
		NoConfirm("待确认"), Confirm("已确认");

		private String display;

		ConfirmStatus(String display) {
			this.display = display;
		}

		public String getDisplay() {
			return display;
		}
	}

	/** 确认日期 */
	@Column
	@Field
	@Between
	private Date confirmDate;

	/** 款项内容 */
	@Column
	private String content;

	/** 是否开票 */
	@Column
	private Boolean isInvoice;

	/** 开票日期 */
	@Column
	@Field
	@Between
	private Date invoiceDate;

	/** 收款单位 */
	@Column
	private String payee;

	/** 付款单位 */
	@Column
	private String payer;

	/** 确认人 */
	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "pkOperator")
	@IndexedEmbedded(depth = 1)
	private CommonUser confirmUser;

	/** 公司名称 */
	private String company;
	
	/**个人姓名*/
	private String perName;
	
	/**联系方式*/
	private String phone;
	
	/** 挂账金额 */
	@Column
	private Double onCreditMoney;
	
	/** 是否销账*/
	private Boolean isSales;
	
	@Version
	private Integer version;

	@JsonSerialize(using = EnumSerializer.class)
	public static enum DataSource {
		GroupReserve("组团"), NonMember("散客"), VisitDoorFIT("上门散客");

		private String display;

		DataSource(String display) {
			this.display = display;
		}

		public String getDisplay() {
			return display;
		}
	}

	/** 入住落实状态，子实体都使用此状态 */
	@JsonSerialize(using = EnumSerializer.class)
	public static enum CheckStatus {
		// 主表
		Initial("初始"), // 初始状态会员签约保存后，自动生成的数据的状态
		Edited("已设置"), // 入住管理员已经完成入住准备要求设置
		Doing("准备中"), // 入住管理员已发起入住准备，各业务部门准备中
		Confirmed("已落实"),

		// 子表
		NoRequiement("无要求"), Pending("待落实"), Pended("已落实");

		private String display;

		CheckStatus(String display) {
			this.display = display;
		}

		public String getDisplay() {
			return display;
		}
	}

	@JsonSerialize(using = EnumSerializer.class)
	public static enum StatementStatus {
		NoStatement("未结算"), Statement("已结算");

		private String display;

		StatementStatus(String display) {
			this.display = display;
		}

		public String getDisplay() {
			return display;
		}
	}
	
		public Long getPkCIImplement() {
		return pkCIImplement;
	}

	public void setPkCIImplement(Long pkCIImplement) {
		this.pkCIImplement = pkCIImplement;
	}

	public ServicePoint getServicePoint() {
		return servicePoint;
	}

	public void setServicePoint(ServicePoint servicePoint) {
		this.servicePoint = servicePoint;
	}

	public GroupReserve getGroupReserve() {
		return groupReserve;
	}

	public void setGroupReserve(GroupReserve groupReserve) {
		this.groupReserve = groupReserve;
	}

	public NonMemGroupReserve getNonMemGroupReserve() {
		return nonMemGroupReserve;
	}

	public void setNonMemGroupReserve(NonMemGroupReserve nonMemGroupReserve) {
		this.nonMemGroupReserve = nonMemGroupReserve;
	}

	public DataSource getDataSource() {
		return dataSource;
	}

	public void setDataSource(DataSource dataSource) {
		this.dataSource = dataSource;
	}

	public Set<RoomPersonalInfo> getRoomPersonalInfos() {
		return roomPersonalInfos;
	}

	public void setRoomPersonalInfos(Set<RoomPersonalInfo> roomPersonalInfos) {
		this.roomPersonalInfos = roomPersonalInfos;
		if (roomPersonalInfos != null) {
			roomPersonalInfos.forEach(a -> a.setCheckInImplement(this));
		}
	}

	public CheckStatus getRoomStatus() {
		return roomStatus;
	}

	public void setRoomStatus(CheckStatus roomStatus) {
		this.roomStatus = roomStatus;
	}

	public CheckInDinner getCheckInDinner() {
		return checkInDinner;
	}

	public void setCheckInDinner(CheckInDinner checkInDinner) {
		this.checkInDinner = checkInDinner;
		if (checkInDinner != null) {
			checkInDinner.setCheckInImplement(this);
		}
	}

	public Set<CheckInCar> getCheckInCar() {
		return checkInCar;
	}

	public void setCheckInCar(Set<CheckInCar> checkInCar) {
		this.checkInCar = checkInCar;
	}

	public SignUpRoom getSignUpRoom() {
		return signUpRoom;
	}

	public void setSignUpRoom(SignUpRoom signUpRoom) {
		this.signUpRoom = signUpRoom;
	}

	public CheckStatus getStatus() {
		return status;
	}

	public void setStatus(CheckStatus status) {
		this.status = status;
	}

	public Integer getVersion() {
		return version;
	}

	public void setVersion(Integer version) {
		this.version = version;
	}

	public StatementStatus getStatementStatus() {
		return statementStatus;
	}

	public void setStatementStatus(StatementStatus statementStatus) {
		this.statementStatus = statementStatus;
	}

	public Date getStatementDate() {
		return statementDate;
	}

	public void setStatementDate(Date statementDate) {
		this.statementDate = statementDate;
	}

	public Integer getSignUpNum() {
		if (roomPersonalInfos==null||roomPersonalInfos.size() == 0) {
			int count = 0;
			if (DataSource.GroupReserve.equals(dataSource)) {	// 老人团
				for (SignUpRegister signUpRegister : groupReserve.getPlanItemGroup().getSignUps()) {
					count += signUpRegister.getExitGroup() == null || !signUpRegister.getExitGroup() ? 1 : 0;
				}
				return count;
			} else {	// 散客团
				if (nonMemGroupReserve.getNonMemberGroup() != null
						&& nonMemGroupReserve.getNonMemberGroup().getSignUps() != null
						&& nonMemGroupReserve.getNonMemberGroup().getSignUps().size() != 0) {
					for (NonMemberRegister nonMemberRegister : nonMemGroupReserve.getNonMemberGroup().getSignUps()) {
						count += nonMemberRegister.getSignUpRegister().getExitGroup() == null
								|| !nonMemberRegister.getSignUpRegister().getExitGroup() ? 1 : 0;
					}
				} else {
					if(nonMemGroupReserve.getNonMemberGroup().getPerNumber() != null){
						return nonMemGroupReserve.getNonMemberGroup().getPerNumber().intValue();
					}else {
						return 0;
					}
				}
				return count;
			}				
		} else {
			int count = 0;
			for (RoomPersonalInfo rpInfo : roomPersonalInfos) {
				if(rpInfo.getSignUpRegister() != null){	// 老人团
					count += rpInfo.getSignUpRegister().getExitGroup() == null
							|| !rpInfo.getSignUpRegister().getExitGroup() ? 1 : 0;
				}else{	// 散客团
					count += rpInfo.getNonMemberRegister().getSignUpRegister().getExitGroup() == null
							|| !rpInfo.getNonMemberRegister().getSignUpRegister().getExitGroup() ? 1 : 0;
				}
			}	
			return count;
		}

	}

	public Set<PaymentMethod> getPaymentMethods() {
		return paymentMethods;
	}

	public void setPaymentMethods(Set<PaymentMethod> paymentMethods) {
		this.paymentMethods = paymentMethods;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}

	public Double getBalance() {
		return balance;
	}

	public void setBalance(Double balance) {
		this.balance = balance;
	}

	public Double getVipPrice() {
		return vipPrice;
	}

	public void setVipPrice(Double vipPrice) {
		this.vipPrice = vipPrice;
	}

	public ConfirmStatus getConfirmStatus() {
		return confirmStatus;
	}

	public void setConfirmStatus(ConfirmStatus confirmStatus) {
		this.confirmStatus = confirmStatus;
	}

	public Date getConfirmDate() {
		return confirmDate;
	}

	public void setConfirmDate(Date confirmDate) {
		this.confirmDate = confirmDate;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	public Boolean getIsInvoice() {
		return isInvoice;
	}

	public void setIsInvoice(Boolean isInvoice) {
		this.isInvoice = isInvoice;
	}

	public Date getInvoiceDate() {
		return invoiceDate;
	}

	public void setInvoiceDate(Date invoiceDate) {
		this.invoiceDate = invoiceDate;
	}

	public String getPayee() {
		return payee;
	}

	public void setPayee(String payee) {
		this.payee = payee;
	}

	public String getPayer() {
		return payer;
	}

	public void setPayer(String payer) {
		this.payer = payer;
	}

	public CommonUser getConfirmUser() {
		return confirmUser;
	}

	public void setConfirmUser(CommonUser confirmUser) {
		this.confirmUser = confirmUser;
	}

	public Set<CarDispatchBill> getCarDispatchBill() {
		return carDispatchBill;
	}

	public void setCarDispatchBill(Set<CarDispatchBill> carDispatchBill) {
		this.carDispatchBill = carDispatchBill;
	}

	public Set<CheckInMeeting> getCheckInMeetings() {
		return checkInMeetings;
	}

	public void setCheckInMeetings(Set<CheckInMeeting> checkInMeetings) {
		this.checkInMeetings = checkInMeetings;
	}

	public String getCompany() {
		return company;
	}

	public void setCompany(String company) {
		this.company = company;
	}

	public String getPerName() {
		return perName;
	}

	public void setPerName(String perName) {
		this.perName = perName;
	}

	public String getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}

	public Double getOnCreditMoney() {
		return onCreditMoney;
	}

	public void setOnCreditMoney(Double onCreditMoney) {
		this.onCreditMoney = onCreditMoney;
	}

	public Boolean getIsSales() {
		return isSales;
	}

	public void setIsSales(Boolean isSales) {
		this.isSales = isSales;
	}

}
